#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <set>

namespace bitrpc
{
    namespace server
    {
        // 服务注册
        class ProviderManager
        {
        public:
            using ptr = std::shared_ptr<ProviderManager>;
            // 服务提供者
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex _mutex;                                       // 互斥锁
                BaseConnection::ptr conn;                                // 提供者连接
                Address host;                                            // 提供者地址
                std::vector<std::string> methods;                        // 提供的方法
                Provider(const BaseConnection::ptr &c, const Address &h) // 构造函数
                    : conn(c), host(h)
                {
                }
                void appendMethod(const std::string &method)
                {
                    //ELOG("服务注册:添加方法");
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.push_back(method); // 添加方法
                    //ELOG("服务注册:添加方法成功");
                }
            };
            // 添加提供者 当一个新的服务提供者进行服务注册的时候调用
            void addProvider(const BaseConnection::ptr &c, const Address &h, const std::string &method)
            {
                Provider::ptr provider;
                // 查找连接所关联的服务提供者对象，找到则获取，找不到则创建，并建立关联
                {
                    //ELOG("服务注册:添加提供者");
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        provider = it->second;
                    }
                    else
                    {
                        provider = std::make_shared<Provider>(c, h);
                        _conns.insert(std::make_pair(c, provider));
                    }
                    // method方法的提供主机要多出一个，_providers新增数据
                    auto &providers = _providers[method]; // 获取method对应的服务提供者列表 如果没有则创建
                    providers.insert(provider);
                    //ELOG("服务注册:添加成功!");
                }

                // 向服务对象中新增一个所能提供的服务名称
                provider->appendMethod(method);
            }
            // 获取提供者 当一个服务提供者断开连接的时候，获取他的信息--用于进行服务下线通知
            Provider::ptr getProvider(const BaseConnection::ptr &c)
            {
                //ELOG("服务注册:获取提供者");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it != _conns.end())
                {
                    return it->second;
                }
                //ELOG("服务注册:没有提供者的信息");
                return Provider::ptr();
            }
            // 删除提供者  当一个服务提供者断开连接的时候，删除它的关联信息
            void delProvider(const BaseConnection::ptr &c)
            {
                //ELOG("服务注册:删除提供者");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c); // 查找连接所关联的服务提供者对象
                if (it == _conns.end())
                {
                    // 当前断开连接的不是一个服务提供者，直接返回
                    return;
                }
                // 如果是提供者，看看提供了什么服务，从服务者提供信息中删除当前服务提供者
                for (auto &method : it->second->methods) // 遍历服务提供者所提供的服务名称
                {
                    auto &providers = _providers[method]; // 获取method对应的服务提供者列表 如果没有则创建
                    providers.erase(it->second);          // 删除提供者
                }
                // 删除连接与提供者的关联
                _conns.erase(it);
                //ELOG("服务注册:删除提供者成功");
            }
            // 获取方法主机  当一个客户端需要调用服务的时候，获取服务提供者地址
            std::vector<Address> methodHosts(const std::string &method)
            {
                //ELOG("服务注册:获取方法主机");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _providers.find(method);
                if (it == _providers.end())
                {
                    return std::vector<Address>();
                }
                std::vector<Address> result; // 直接返回服务提供者列表(构造)
                for (auto &provider : it->second)
                {
                    result.push_back(provider->host);
                }
                //ELOG("服务注册:获取方法主机成功");
                return result;
            }

        private:
            std::mutex _mutex;                                                   // 互斥锁
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers; // 方法与提供者映射
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;       // 连接与提供者映射
        };

        // 服务发现者管理器
        class DiscovererManager
        {
        public:
            using ptr = std::shared_ptr<DiscovererManager>;
            //发现者
            struct Discoverer
            {
                using ptr = std::shared_ptr<Discoverer>;
                std::mutex _mutex;                       // 互斥锁
                BaseConnection::ptr conn;                // 发现者关联的客户端连接
                std::vector<std::string> methods;        // 发现过的服务名称
                Discoverer(const BaseConnection::ptr &c) // 构造函数
                    : conn(c)
                {
                }
                void appendMethod(const std::string &method) // 添加方法
                {
                    //ELOG("服务发现:添加方法");
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.push_back(method);
                }
            };
            // 当每次客户端进行服务发现的时候新增一个发现者,新增服务名称
            Discoverer::ptr addDiscoverer(const BaseConnection::ptr &c, const std::string &method)
            {
                //ELOG("服务发现:添加发现者");
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        discoverer = it->second;
                    }
                    else
                    {
                        discoverer = std::make_shared<Discoverer>(c); // 创建发现者
                        _conns.insert(std::make_pair(c, discoverer)); // 将连接与发现者关联
                    }
                    auto &discoverers = _discoverers[method]; // 获取method对应的服务发现者列表 如果没有则创建
                    discoverers.insert(discoverer);           // 将发现者添加到列表中
                }
                discoverer->appendMethod(method); // 将方法添加到发现者中
                //ELOG("服务发现:添加发现者成功");
                return discoverer;
            }
            // 当客户端断开连接的时候,找到发现者信息,删除关联数据
            void delDiscoverer(const BaseConnection::ptr &c)
            {
                //ELOG("服务发现:删除发现者");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    // 没有找到连接对应的发现者信息，代表客户端不是一个服务发现者
                    return;
                }
                for (auto &method : it->second->methods)
                {
                    auto discoverers = _discoverers[method]; // 获取method对应的服务发现者列表
                    discoverers.erase(it->second);           // 将发现者从列表中删除
                }
                _conns.erase(it); // 将连接与发现者关联信息删除
                //ELOG("服务发现:删除发现者成功");
            }
            // 当有一个新服务提供者上线,则进行上线通知
            void onlineNotify(const std::string &method, const Address &host)
            {
                //ELOG("服务发现:上线通知");
                return notify(method, host, ServiceOptype::SERVICE_ONLINE); // 服务上线通知
            }
            // 当有一个服务提供者下线,则进下线行通知
            void offlineNotify(const std::string &method, const Address &host)
            {
                //ELOG("服务发现:下线通知");
                return notify(method, host, ServiceOptype::SERVICE_OFFLINE); // 服务下线通知
            }

        private:
            // 通知服务发现者
            void notify(const std::string &method, const Address &host, ServiceOptype optype)
            {
                //ELOG("服务发现:通知");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _discoverers.find(method);
                if (it == _discoverers.end())
                {
                    // 这个服务没有发现者，则不需要通知
                    return;
                }
                auto msg_req = MessageFactory::create<ServiceRequest>();
                msg_req->setMethod(method);
                msg_req->setHost(host);
                msg_req->setId(UUID::uuid());
                msg_req->setMType(MType::REQ_SERVICE);
                msg_req->setOptype(optype);
                // 遍历发现者列表，将服务地址发送给发现者
                for (auto &discoverer : it->second)
                {
                    discoverer->conn->send(msg_req); // 发送服务上线通知
                }
                //ELOG("服务发现:通知成功");
            }

        private:
            std::mutex _mutex;                                                       // 互斥锁
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _discoverers; // 方法与发现者映射
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;         // 连接与发现者映射
        };
        
        //注册与发现管理器
        class PDManager
        {
        public:
            using ptr = std::shared_ptr<PDManager>;
            PDManager()
                : _providers(std::make_shared<ProviderManager>()), _discoverers(std::make_shared<DiscovererManager>())
            {
            }

            // 对不同的服务请求进行处理给DiscovererManager
            void onServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                //ELOG("服务发现:请求到来");
                // 服务操作请求:服务注册,服务发现
                ServiceOptype optype = msg->optype(); // 获取服务操作类型
                if (optype == ServiceOptype::SERVICE_REGISTRY)
                {
                    // 服务注册
                    //   1. 新增服务提供者；  2. 进行服务上线的通知
                    ILOG("%s:%d 注册服务 %s", msg->host().first.c_str(), msg->host().second, msg->method().c_str());
                    _providers->addProvider(conn, msg->host(), msg->method());// 注册服务
                    _discoverers->onlineNotify(msg->method(), msg->host());// 通知服务上线
                    return registryResponse(conn, msg); // 注册响应
                }
                else if (optype == ServiceOptype::SERVICE_DISCOVERY)
                {
                    // 服务发现
                    //   1. 新增服务发现者
                    ILOG("客户端要进行 %s 服务发现！", msg->method().c_str());
                    _discoverers->addDiscoverer(conn, msg->method()); // 哪个服务端对哪个服务进行发现
                    return discoverResponse(conn, msg);               // 发现响应
                }
                else
                {
                    ELOG("收到服务操作请求,但是操作类型错误!");
                    return errorResponse(conn, msg); // 错误响应
                }
            }
            // 服务连接断开的
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                //ELOG("服务连接断开");
                auto provider = _providers->getProvider(conn); // 获取提供者
                if (provider.get() != nullptr)
                {
                    ILOG("%s:%d 服务下线", provider->host.first.c_str(), provider->host.second);
                    for (auto &method : provider->methods)
                    {
                        _discoverers->offlineNotify(method, provider->host); // 通知服务下线
                    }
                    _providers->delProvider(conn); // 删除提供者
                }
                _discoverers->delDiscoverer(conn); // 删除发现者
            }

        private:
            void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                //ELOG("收到服务操作请求!");
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setRCode(RCode::RCODE_INVALID_OPTYPE);    // 无效操作类型
                msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW); // 未知错误
                conn->send(msg_rsp);
            }

            // 服务注册响应
            void registryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                //ILOG("服务注册响应");
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY); // 服务注册
                conn->send(msg_rsp);
            }
            // 服务发现响应
            void discoverResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                //ILOG("服务发现响应");
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVERY); // 服务发现
                std::vector<Address> hosts = _providers->methodHosts(msg->method());
                if (hosts.empty()) // 没有找到服务
                {
                    msg_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->send(msg_rsp);
                }

                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setMethod(msg->method());
                msg_rsp->setHost(hosts);
                return conn->send(msg_rsp);
            }

        private:
            ProviderManager::ptr _providers;     // 提供者管理器
            DiscovererManager::ptr _discoverers; // 发现者管理器
        };
    }
}